import traceback

from api import zabbix_api62, netbox_api
from api.universal import change_datetime

# logger = logging.getLogger('netbox')
from loguru import logger

logger.add("/var/log/Task/netbox/update_virtual.log", rotation="00:00", backtrace=True, diagnose=True,
           level="DEBUG", retention='90 days')


def zabbix_update_virtual(host_data, netbox_token, verify, token, zabbix_server_url, father_template_group, netbox_url):
    """
    更新zabbix虚拟机监控
    """
    try:
        status = "None"
        # 判断设备状态
        if host_data["status"]["label"] == "Active" or host_data["status"]["label"] == "Staged":
            host_status = 0
        else:
            host_status = 1
        # 设备名称
        hostname = host_data["name"]
        if host_data.get("site"):
            # 获取站点信息
            if host_data['site']['url'].startswith("http"):
                site_url = host_data['site']['url']
            else:
                site_url = netbox_url + host_data['site']['url']
            site_info = netbox_api.netbox_get_next(netbox_token, site_url, verify)
            # 站点代码
            site_code = site_info.get("slug")
            # 判断站点状态，如果站点状态为offing，则不同步host
            if site_info["status"]["value"] in ["retired"]:
                logger.info(
                    f"设备{hostname} 所属站点{site_info['name']} 状态为: {site_info['status']['value']}, 不进行同步")
                resp_data = {
                    "status": status,
                    "hostname": host_data["name"],
                }
                logger.info("站点状态offing， 不同步hosts")
                return resp_data
        else:
            site_code = None
            site_info = {"name": None, "status": {"label": None, "value": None}}
        # 所属部门
        if host_data.get("tenant"):
            department = str(host_data["tenant"]["name"])
        else:
            department = None
        # 最后更新时间
        last_updated = host_data['last_updated']
        last_date = change_datetime(last_updated)
        device_priority = host_data['custom_fields']['Priority']
        if not device_priority:
            device_priority = 'P4'

        # 平台 platform
        if host_data.get("platform"):
            platform = host_data["platform"].get("name")
        else:
            platform = None
        # cluster
        cluster = host_data["cluster"].get("name")
        # 设备角色
        host_role = host_data["role"].get("slug")
        # netbox 信息同步至zabbix相关项
        macros = [
            {
                "macro": "{$NETBOX_ID}",
                "value": "netbox_" + 'virtual-' + str(host_data['id']) + "_end"
            },
            {
                "macro": "{$UPDATA_DATE}",
                "value": last_updated
            },
            {
                "macro": "{$SITE_CODE}",
                "value": str(site_code)
            },
            {
                "macro": "{$SITE_NAME}",
                "value": str(site_info['name'])
            },
            {
                "macro": "{$SITE_STATUS}",
                "value": str(site_info['status']['label']),
                "description": str(site_info['status']['value'])
            },
            {
                "macro": "{$DEVICE_STATUS}",
                "value": str(host_data['status']['label']),
                "description": str(host_data['status']['value'])
            },
            {
                "macro": "{$DEVICE_ROLE}",
                "value": 'host_' + host_role,
            },
            {
                "macro": "{$DEPARTMENT}",
                "value": str(department)
            },
            {
                "macro": "{$CLUSTER}",
                "value": str(cluster)
            },
            {
                "macro": "{$PLATFORM}",
                "value": str(platform)
            },
            {
                "macro": "{$NETBOX_MODULE}",
                "value": "VM",
            }
        ]

        inventory = {
            "poc_1_name": department,
            "location": site_info.get('physical_address'),
            "location_lat": site_info.get('latitude'),
            "location_lon": site_info.get('longitude')
        }

        tags = [
            {
                "tag": "department",
                "value": str(department)
            },
            {
                "tag": "device_status",
                "value": str(host_data['status']['label'])
            },
            {
                "tag": "sitecode",
                "value": str(site_code)
            },
            {
                "tag": "site_status",
                "value": str(site_info['status']['label']),
            },
            {
                "tag": "device_role",
                "value": 'host_' + host_role
            },
            {
                "tag": "cluster",
                "value": str(cluster)
            },
            {
                "tag": "platform",
                "value": str(platform)
            },
            {
                "tag": "netbox_module",
                "value": "VM",
            }
        ]
        host_name = host_data["name"]
        # 接口
        snmp_list = ['ClearPass', 'ESXi']
        if host_data["platform"] and host_data["platform"]["name"] in snmp_list or host_role in ['LDDI', 'MDDI', 'ADNS']:
            port_type = 2
        else:
            port_type = 1

        template = device_priority + ' ' + host_role + ' ' + str(platform)

        # 集群组
        group_cluster_name = cluster
        group_cluster_info = zabbix_api62.zabbix_get_group(token, zabbix_server_url, "name", group_cluster_name + "*",
                                                           False)
        if group_cluster_info:
            group_cluster_id = group_cluster_info[0].get("groupid")
        else:
            ret = zabbix_api62.zabbix_create_group(token, zabbix_server_url, group_cluster_name)
            group_cluster_id = ret['result']['groupids'][0]
            logger.info(f"新建分组:{group_cluster_name}")

        # 模板组
        group_template_name = template
        group_template_info = zabbix_api62.zabbix_get_group(token, zabbix_server_url, "name", group_template_name + "*",
                                                            False)
        if group_template_info:
            group_template_id = group_template_info[0].get('groupid')
        else:
            ret = zabbix_api62.zabbix_create_group(token, zabbix_server_url, group_template_name)
            group_template_id = ret['result']['groupids'][0]
            logger.info(f"新建分组:{group_template_name}")

        # 站点组
        if host_data["site"]:
            group_site_name = f"{site_code}-{host_data['site']['name']}"
            group_site_info = zabbix_api62.zabbix_get_group(token, zabbix_server_url, "name", group_site_name + "*", False)

            if not group_site_info:
                logger.error(f"未找到分组:{group_site_name}")
                resp_data = {"status": "Error", "message": "设备更新失败", "detail": f"未找到分组{group_site_name}",
                             "hostname": host_name}
                return resp_data
            group_site_id = group_site_info[0]["groupid"]
            group_id_list = [group_site_id, group_template_id, group_cluster_id]
        else:
            group_id_list = [group_template_id, group_cluster_id]
        if department == 'ITOB':
            itob_group = zabbix_api62.zabbix_get_group(token, zabbix_server_url, 'name', '7000-ITOB-Devices', False)
            group_id_list.append(itob_group[0]['groupid'])
        elif department == 'ITSEC':
            itsec_group = zabbix_api62.zabbix_get_group(token, zabbix_server_url, 'name', '8000-ITSEC-Devices',
                                                        False)
            group_id_list.append(itsec_group[0]['groupid'])
        template_info = zabbix_api62.zabbix_get_templates(token, zabbix_server_url, 'host', template)
        if template_info:
            template_id = template_info[0]['templateid']
        else:
            logger.info(f"未找到模板，创建模板:{template}")
            tmp_group_info = zabbix_api62.zabbix_get_templategroup(token, zabbix_server_url, father_template_group)
            if tmp_group_info:
                tmp_group_id = tmp_group_info[0]['groupid']
                template_info = zabbix_api62.zabbix_create_template(token, zabbix_server_url, tmp_group_id,
                                                                    template)
                if template_info.get("status") == "Error":
                    return template_info
                template_id = template_info['templateids'][0]
            else:
                logger.error(f"请创建templates group:{father_template_group}, Templates")
                status = "Error"
                resp_data = {"status": status, "message": "更新失败",
                             "detail": f'error:请创建templates group:{father_template_group}',
                             "hostname": host_name}
                return resp_data
        # 扩展模板处理
        template_list = []
        if host_data["custom_fields"].get("ExtendedTemplate"):
            if type(template_info) == list:
                template_list.append({"templateid": template_info[0]["templateid"]})
            if type(template_info) == dict:
                template_list.append({"templateid": template_info["templateid"][0]})
            expand_template_group = "Template Service Group"
            for extemplate_name in host_data["custom_fields"]["ExtendedTemplate"]:
                extemplate_template_info = zabbix_api62.zabbix_get_templates(token, zabbix_server_url, 'host',
                                                                             extemplate_name)
                if extemplate_template_info:
                    template_list.append({"templateid": extemplate_template_info[0]['templateid']})
                else:
                    logger.info(f"未找到模板{extemplate_name}, 检查模板组:{expand_template_group}")
                    extemplate_template_group_info = zabbix_api62.zabbix_get_group(token, zabbix_server_url, 'name',
                                                                                   expand_template_group, False)
                    if extemplate_template_group_info:
                        logger.info(f"{expand_template_group}模板组正常")
                        extemplate_template_group_id = extemplate_template_group_info[0]["groupid"]
                    else:
                        logger.info(f"未找到模版组{expand_template_group},创建中···")
                        # 创建扩展模板组
                        create_group_ret = zabbix_api62.zabbix_create_group(token, zabbix_server_url,
                                                                            expand_template_group, verify)
                        extemplate_template_group_id = create_group_ret["result"]["groupids"][0]
                    # 创建模板
                    create_extemplate_template = zabbix_api62.zabbix_create_template(token, zabbix_server_url,
                                                                                     extemplate_template_group_id,
                                                                                     extemplate_name)
                    logger.info(f"创建模板:{extemplate_name},结果：{create_extemplate_template}")
                    template_list.append({"templateid": create_extemplate_template['templateids'][0]})
        # 获取IP
        managementip = host_data['custom_fields']['ManagementIP']
        if template_list:
            template_id = template_list
        # 创建或修改主机
        resp_data = zabbix_create_or_update_host(host_data, managementip, group_id_list,
                                                 template_id, port_type, macros, host_data['id'], inventory,
                                                 tags, host_status, 1, token, zabbix_server_url, last_date)
        return resp_data
    except Exception as e:
        resp_data = {
            "status": "Error",
            "message": "更新失败",
            "detail": traceback.format_exc(),
            "hostname": host_data["name"]
        }
        logger.exception(traceback.format_exc())
        return resp_data


def zabbix_create_or_update_host(host_data, hostIP, group_id, template_id, port_type, macros, netbox_id, inventory, tags,
                                 host_status, forcibly_update, token, zabbix_server_url, last_date):
    try:
        if not netbox_id:
            netbox_id = 0
        search_info = {
            "macro": "{$NETBOX_ID}",
            "value": "netbox_" + "virtual-" + str(netbox_id) + "_end"
        }
        search_ret = zabbix_api62.zabbix_get_macros(token, zabbix_server_url, 'search', search_info)
        host_ret = zabbix_api62.zabbix_get_hosts(token, zabbix_server_url, "host", host_data['name'])
        if 'result' in search_ret:
            if not search_ret["result"] and not host_ret["result"]:
                if host_data['status']["label"] == "Active" or host_data['status']["label"] == "Staged" or \
                        host_data['status']["label"] == "Planned":
                    logger.info(f"正在创建zabbix_host：{host_data['name']}")
                    resp_data = zabbix_api62.zabbix_create_host(token, zabbix_server_url, hostIP, host_data['name'], group_id,
                                                                template_id,
                                                                port_type, macros, inventory, tags, host_status)
                    if resp_data.get("status") == "Error":
                        return resp_data
                    resp_data["hostname"] = host_data['name']
                else:
                    resp_data = {"status": "None", "hostname": host_data['name'],
                                 "message": f"该设备状态为{host_data['status']['label']}，不进行创建",
                                 "detail": f"该设备状态为{host_data['status']['label']}，不进行创建"}
                    return resp_data
            else:
                # 检查是否存在重名设备
                if not search_ret.get("result") and host_ret.get("result"):
                    search_ret = host_ret
                logger.info(f"host:{host_data['name']}已存在，检查更新")
                macros_ret = zabbix_api62.zabbix_get_macros(token, zabbix_server_url, 'hostids',
                                                            search_ret['result'][0]['hostid'])
                # 判断netbox线路更新时间是否比zabbix新
                zabbix_data = None
                for x in macros_ret["result"]:
                    if x["macro"] == '{$UPDATA_DATE}':
                        updata_date = x["value"]
                        zabbix_data = change_datetime(updata_date)
                if forcibly_update or (zabbix_data and last_date > zabbix_data) or not zabbix_data:
                    resp_data = zabbix_update_host(search_ret['result'][0]['hostid'], hostIP, host_data['name'], '',
                                                   group_id, template_id, port_type, macros, inventory, tags,
                                                   host_status, token, zabbix_server_url)
                else:
                    logger.info(f"{host_data['name']} 未检测到更新")
                    resp_data = {"status": "None", "hostname": host_data['name'], "message": "未检测到更新",
                                 "detail": "设备未检测到更新"}
        else:
            resp_data = {"status": "None", "hostname": host_data['name'], "message": "未找到自定义宏",
                         "detail": "未找到自定义宏"}
        # return resp_data
    except Exception as e:
        resp_data = {"status": "Error", "message": "设备更新失败", "detail": traceback.format_exc(),
                     "hostname": host_data['name']}
    return resp_data


def zabbix_update_host(hostid, hostip, hostname, name, group_id, templateid, port_type, macros, inventory, tags,
                       host_status, token, zabbix_server_url):
    try:
        resp_data = {
            "status": "Update",
            "hostname": hostname
        }
        logger.info(f'host:{hostname}开始更新')
        groups_list = [{"groupid": i} for i in group_id]
        # 获取host接口ID
        zabbix_ret = zabbix_api62.zabbix_get_hostinterface(token, zabbix_server_url, hostid)
        # 更新监控非IP信息
        update_ret1 = zabbix_api62.zabbix_update_line(token, zabbix_server_url, hostid, hostip, hostname, name,
                                                      groups_list,
                                                      templateid, port_type, macros, inventory, tags, host_status)
        if "error" in update_ret1 and update_ret1["error"]["data"].startswith("Item prototype") and \
                update_ret1["error"]["data"].endswith("linked to another rule."):
            template_info = zabbix_api62.zabbix_get_host_templatesid(zabbix_server_url, hostid, token)
            for i in template_info[0]["parentTemplates"]:
                clear_templateid = i["templateid"]
                clear_templates = zabbix_api62.zabbix_templates_clear(token, zabbix_server_url, hostid, name,
                                                                      clear_templateid)
            update_ret1 = zabbix_api62.zabbix_update_line(token, zabbix_server_url, hostid, hostip, hostname, name,
                                                          groups_list, templateid, port_type, macros, inventory, tags,
                                                          host_status)
        # 比较IP，如有更改，则更新IP
        if hostip != zabbix_ret['result'][0]['ip']:
            resp_data = zabbix_api62.zabbix_uptade_hostinterface(token, zabbix_server_url,
                                                                 zabbix_ret['result'][0]['interfaceid'], hostip)
            print('line' + name + ' IP信息已更新')
            resp_data["hostname"] = hostname
            logger.info('line' + name + ' IP信息已更新')
        return resp_data
    except Exception as e:
        resp_data = {
            "status": "Error",
            "message": "更新主机失败",
            "detail": traceback.format_exc(),
            "hostname": hostname
        }
        logger.exception(traceback.format_exc())
        return resp_data
